import pygame
import sys
import os
import json
from src.game import Game
from src.keystroke_visualization import KeystrokeVisualization

font_path = "assets/fonts/KeLaiYinLanDeYeWan-2.ttf"

class MainMenu:
    def __init__(self, screen):
        self.screen = screen
        self.fullscreen = False  # 是否全屏
        self.font_size = 48  # 默认字体大小
        self.option_spacing = 25  # 相邻选项间距改为 25 像素
        self.back_button_padding = (20, 10)  # 返回按钮边距

        # 加载外部字体文件
        self.font = pygame.font.Font(font_path, self.font_size)  # 使用外部字体
        self.options = [
            "开始游戏",
            "击键特征可视化",
            "退出游戏"
        ]
        self.sub_options = {
            "开始游戏": ["新用户", "已有用户"]  # 删除 "管理员" 选项
        }
        self.current_menu = "main"  # 当前菜单状态
        self.selected_index = 0  # 当前选中的选项索引
        self.hovered_index = None  # 当前鼠标悬停的选项索引
        self.back_button_rect = None  # 返回按钮的矩形区域
        self.back_button_hovered = False  # 返回按钮是否悬停
        self.input_name_active = False  # 是否正在输入姓名
        self.input_name = ""  # 用户输入的姓名
        self.temp_subject = None  # 临时存储用户输入的 subject
        self.running = True  # 控制主循环是否运行
        self.name_error_message = ""  # 昵称错误提示信息
        self.error_font = pygame.font.Font(font_path, 20)  # 错误信息字体大小为 20
        self.all_subjects = self.get_all_subjects()  # 提取所有 subject 并去重

    def get_all_subjects(self):
        """提取 database.json 中的所有 subject 并去重（保持顺序）"""
        subjects = []
        if os.path.exists("assets/database/main_database.json"):
            with open("assets/database/main_database.json", "r", encoding="utf-8") as file:
                data = json.load(file)
                seen = set()
                for user in data:
                    subject = str(user["subject"])
                    if subject not in seen:
                        subjects.append(subject)
                        seen.add(subject)
        print("当前数据库中的 subject 列表:", subjects)  # 输出 subject 列表的调试信息
        return subjects

    def check_screen_size(self):
        """检测屏幕大小并调整字体大小"""
        screen_width, screen_height = self.screen.get_size()
        desktop_width, desktop_height = pygame.display.get_desktop_sizes()[0]
        
        # 视为全屏的条件可以放宽一些
        if screen_width > desktop_width * 0.9 or screen_height > desktop_height * 0.9:
            self.font_size = 72
            self.option_spacing = 25
            self.fullscreen = True
        else:
            self.font_size = 48
            self.option_spacing = 25
            self.fullscreen = False
        
        # 重新加载字体
        self.font = pygame.font.Font(font_path, self.font_size)
        self.error_font = pygame.font.Font(font_path, self.font_size // 2)

    def draw(self):
        if not self.running:  # 如果主循环已停止，不再绘制
            return
        
        self.check_screen_size()  # 每次绘制前检查屏幕大小
        
        try:
            self.screen.fill((255, 255, 255))  # 清屏

            # 绘制当前菜单的选项
            if self.current_menu == "main":
                self.draw_main_menu()
            elif self.current_menu == "sub":
                self.draw_sub_menu()

            # 如果不是主菜单，绘制返回按钮
            if self.current_menu != "main":
                self.draw_back_button()

            # 如果正在输入姓名，绘制输入框和确认按钮
            if self.input_name_active:
                self.draw_name_input()

            pygame.display.flip()
        except pygame.error:  # 捕获 Surface 已销毁的错误
            self.running = False

    def draw_main_menu(self):
        """绘制主菜单"""
        screen_width, screen_height = self.screen.get_size()
        for i, option in enumerate(self.options):
            # 动态计算文本大小（包括边距）
            text_surface = self.font.render(option, True, (0, 0, 0))
            text_width, text_height = text_surface.get_size()
            text_rect = pygame.Rect(0, 0, text_width + 20, text_height + 10)  # 增加边距

            # 根据中间选项确定位置
            middle_index = len(self.options) // 2
            y_offset = (i - middle_index) * (self.option_spacing + text_rect.height)
            text_rect.center = (screen_width // 2, screen_height // 2 + y_offset)

            self.screen.blit(text_surface, text_surface.get_rect(center=text_rect.center))

            # 如果鼠标悬停在选项上，绘制高亮效果
            if i == self.hovered_index:
                pygame.draw.rect(self.screen, (255, 255, 0), text_rect, 3)

    def draw_sub_menu(self):
        """绘制子菜单"""
        screen_width, screen_height = self.screen.get_size()
        sub_options = self.sub_options.get(self.options[self.selected_index], [])
        for i, option in enumerate(sub_options):
            # 动态计算文本大小（包括边距）
            text_surface = self.font.render(option, True, (0, 0, 0))
            text_width, text_height = text_surface.get_size()
            text_rect = pygame.Rect(0, 0, text_width + 20, text_height + 10)  # 增加边距

            # 根据中间选项确定位置
            middle_index = len(sub_options) // 2
            y_offset = (i - middle_index) * (self.option_spacing + text_rect.height)
            text_rect.center = (screen_width // 2, screen_height // 2 + y_offset)

            self.screen.blit(text_surface, text_surface.get_rect(center=text_rect.center))

            # 如果鼠标悬停在选项上，绘制高亮效果
            if i == self.hovered_index:
                pygame.draw.rect(self.screen, (255, 255, 0), text_rect, 3)

    def draw_back_button(self):
        """绘制返回按钮"""
        screen_width, screen_height = self.screen.get_size()
        back_text = self.font.render("返回", True, (0, 0, 0))
        back_rect = back_text.get_rect(bottomright=(screen_width - 20, screen_height - 20))

        # 增加边距
        back_rect.width += self.back_button_padding[0]
        back_rect.height += self.back_button_padding[1]
        back_rect.center = (screen_width - 20 - back_rect.width // 2, screen_height - 20 - back_rect.height // 2)

        # 如果鼠标悬停在返回按钮上，绘制高亮效果
        if self.back_button_hovered:
            pygame.draw.rect(self.screen, (255, 255, 0), back_rect, 3)

        self.screen.blit(back_text, back_text.get_rect(center=back_rect.center))
        self.back_button_rect = back_rect

    def draw_name_input(self):
        self.screen.fill((255, 255, 255))  # 清屏
        screen_width, screen_height = self.screen.get_size()

        # 根据窗口大小动态调整字体大小
        input_font_size = 48 if not self.fullscreen else 72
        input_font = pygame.font.Font(font_path, input_font_size)
        error_font_size = 24 if not self.fullscreen else 36
        error_font = pygame.font.Font(font_path, error_font_size)

        # 提示词位置
        prompt_text = input_font.render("请输入您的昵称（1-10个字符）：", True, (0, 0, 0))
        prompt_rect = prompt_text.get_rect(center=(screen_width // 2, screen_height // 3))

        # 输入框位置
        input_width = int(screen_width * 0.6)
        input_height = int(screen_height * 0.08)
        input_rect = pygame.Rect(0, 0, input_width, input_height)
        input_rect.center = (screen_width // 2, screen_height // 2 - 30)

        # 按钮位置（下移并增加间距）
        button_width = int(screen_width * 0.15)
        button_height = int(screen_height * 0.08)
        confirm_rect = pygame.Rect(0, 0, button_width, button_height)
        confirm_rect.center = (screen_width // 2 - button_width - 20, screen_height // 2 + 100)  # 左移确认按钮
        
        back_rect = pygame.Rect(0, 0, button_width, button_height)
        back_rect.center = (screen_width // 2 + button_width + 20, screen_height // 2 + 100)  # 右移返回按钮

        # 错误提示位置（紧贴输入框下方）
        error_y = input_rect.bottom + 10

        # 绘制提示词
        self.screen.blit(prompt_text, prompt_rect)

        # 绘制输入框
        pygame.draw.rect(self.screen, (200, 200, 200), input_rect)
        name_text = input_font.render(self.input_name, True, (0, 0, 0))
        self.screen.blit(name_text, (input_rect.x + 15, input_rect.y + (input_height - name_text.get_height()) // 2))

        # 绘制确认按钮
        pygame.draw.rect(self.screen, (0, 200, 0), confirm_rect)
        confirm_text = input_font.render("确认", True, (0, 0, 0))
        self.screen.blit(confirm_text, confirm_text.get_rect(center=confirm_rect.center))

        # 绘制返回按钮
        pygame.draw.rect(self.screen, (200, 0, 0), back_rect)
        back_text = input_font.render("返回", True, (0, 0, 0))
        self.screen.blit(back_text, back_text.get_rect(center=back_rect.center))

        # 高亮效果
        mouse_pos = pygame.mouse.get_pos()
        if confirm_rect.collidepoint(mouse_pos):
            pygame.draw.rect(self.screen, (255, 255, 0), confirm_rect, 3)
        if back_rect.collidepoint(mouse_pos):
            pygame.draw.rect(self.screen, (255, 255, 0), back_rect, 3)

        # 绘制错误提示信息（紧贴输入框下方）
        if self.name_error_message:
            error_text = error_font.render(self.name_error_message, True, (255, 0, 0))
            error_rect = error_text.get_rect(midtop=(input_rect.centerx, error_y))
            self.screen.blit(error_text, error_rect)

        # 保存按钮rect用于点击检测
        self.confirm_button_rect = confirm_rect
        self.back_button_rect = back_rect
        self.input_rect = input_rect

    def handle_event(self, event):
        """处理事件"""
        if event.type == pygame.MOUSEBUTTONDOWN:
            if self.input_name_active:
                self.handle_name_input_click(event)
            elif self.current_menu == "main":
                self.handle_main_menu_click(event)
            else:
                self.handle_sub_menu_click(event)
        elif event.type == pygame.MOUSEMOTION:
            self.handle_mouse_motion(event)
        elif event.type == pygame.KEYDOWN and self.input_name_active:
            self.handle_name_input_key(event)
        elif event.type == pygame.VIDEORESIZE:
            self.handle_resize(event)
        elif event.type == pygame.QUIT:  # 处理退出事件
            self.running = False  # 停止主循环
            pygame.quit()
            sys.exit()  # 正常退出程序

    def handle_main_menu_click(self, event):
        """处理主菜单的点击事件"""
        screen_width, screen_height = self.screen.get_size()
        for i, option in enumerate(self.options):
            # 动态计算文本大小（包括边距）
            text_surface = self.font.render(option, True, (0, 0, 0))
            text_width, text_height = text_surface.get_size()
            text_rect = pygame.Rect(0, 0, text_width + 20, text_height + 10)  # 增加边距

            # 根据中间选项确定位置
            middle_index = len(self.options) // 2
            y_offset = (i - middle_index) * (self.option_spacing + text_rect.height)
            text_rect.center = (screen_width // 2, screen_height // 2 + y_offset)

            if text_rect.collidepoint(event.pos):
                self.selected_index = i
                if self.options[i] in self.sub_options:
                    self.current_menu = "sub"
                else:
                    self.execute_option(self.options[i])
                break

    def handle_sub_menu_click(self, event):
        """处理子菜单的点击事件"""
        screen_width, screen_height = self.screen.get_size()
        sub_options = self.sub_options.get(self.options[self.selected_index], [])
        for i, option in enumerate(sub_options):
            # 动态计算文本大小（包括边距）
            text_surface = self.font.render(option, True, (0, 0, 0))
            text_width, text_height = text_surface.get_size()
            text_rect = pygame.Rect(0, 0, text_width + 20, text_height + 10)  # 增加边距

            # 根据中间选项确定位置
            middle_index = len(sub_options) // 2
            y_offset = (i - middle_index) * (self.option_spacing + text_rect.height)
            text_rect.center = (screen_width // 2, screen_height // 2 + y_offset)

            if text_rect.collidepoint(event.pos):
                self.execute_sub_option(option)
                break

        # 检查是否点击了返回按钮
        if self.back_button_rect and self.back_button_rect.collidepoint(event.pos):
            self.current_menu = "main"

    def handle_name_input_click(self, event):
        """处理姓名输入框的点击事件"""
        # 如果点击了确认按钮
        if hasattr(self, 'confirm_button_rect') and self.confirm_button_rect.collidepoint(event.pos):
            if self.validate_name():
                self.temp_subject = self.input_name
                self.input_name_active = False
                # 修改这里：传递用户名
                self.start_game("新用户", username=self.input_name)  # 传入用户名
        
        # 如果点击了返回按钮
        if hasattr(self, 'back_button_rect') and self.back_button_rect.collidepoint(event.pos):
            self.input_name_active = False
            self.input_name = ""
            self.name_error_message = ""

    def handle_name_input_key(self, event):
        """处理姓名输入框的键盘事件"""
        if event.key == pygame.K_RETURN:  # 按下 Enter 键
            if self.validate_name():
                self.temp_subject = self.input_name  # 临时存储用户输入的 subject
                self.input_name_active = False  # 关闭输入框
                # 修改这里：传递用户名
                self.start_game("新用户", username=self.input_name)  # 传入用户名
        elif event.key == pygame.K_BACKSPACE:  # 按下退格键
            self.input_name = self.input_name[:-1]
            self.name_error_message = ""  # 清空错误提示
        else:
            if event.unicode.isalnum():
                self.input_name += event.unicode  # 输入字符
                self.name_error_message = ""  # 清空错误提示

    def validate_name(self):
        """验证昵称是否符合要求"""
        if len(self.input_name) == 0:
            self.name_error_message = "昵称不能为空"
            return False
        elif len(self.input_name) > 10:
            self.name_error_message = "文本过长"
            return False
        elif self.input_name in self.all_subjects:
            self.name_error_message = "昵称已存在，请重新输入"
            return False
        return True

    def handle_mouse_motion(self, event):
        """处理鼠标移动事件"""
        screen_width, screen_height = self.screen.get_size()
        self.hovered_index = None
        self.back_button_hovered = False

        if self.current_menu == "main":
            for i, option in enumerate(self.options):
                # 动态计算文本大小（包括边距）
                text_surface = self.font.render(option, True, (0, 0, 0))
                text_width, text_height = text_surface.get_size()
                text_rect = pygame.Rect(0, 0, text_width + 20, text_height + 10)  # 增加边距

                # 根据中间选项确定位置
                middle_index = len(self.options) // 2
                y_offset = (i - middle_index) * (self.option_spacing + text_rect.height)
                text_rect.center = (screen_width // 2, screen_height // 2 + y_offset)

                if text_rect.collidepoint(event.pos):
                    self.hovered_index = i
                    break
        else:
            sub_options = self.sub_options.get(self.options[self.selected_index], [])
            for i, option in enumerate(sub_options):
                # 动态计算文本大小（包括边距）
                text_surface = self.font.render(option, True, (0, 0, 0))
                text_width, text_height = text_surface.get_size()
                text_rect = pygame.Rect(0, 0, text_width + 20, text_height + 10)  # 增加边距

                # 根据中间选项确定位置
                middle_index = len(sub_options) // 2
                y_offset = (i - middle_index) * (self.option_spacing + text_rect.height)
                text_rect.center = (screen_width // 2, screen_height // 2 + y_offset)

                if text_rect.collidepoint(event.pos):
                    self.hovered_index = i
                    break

        # 检查鼠标是否悬停在返回按钮上
        if self.back_button_rect and self.back_button_rect.collidepoint(event.pos):
            self.back_button_hovered = True

    def handle_resize(self, event):
        self.screen = pygame.display.set_mode((event.w, event.h), pygame.RESIZABLE)
        # 动态调整字体大小和选项间距
        if event.w > 800 and event.h > 600:  # 视为最大化
            self.font_size = 72
            self.option_spacing = 25  # 相邻选项间距改为 25 像素
            self.fullscreen = True
        else:  # 窗口模式
            self.font_size = 48
            self.option_spacing = 25  # 相邻选项间距改为 25 像素
            self.fullscreen = False
        self.font = pygame.font.Font(os.path.join("assets", "fonts", "KeLaiYinLanDeYeWan-2.ttf"), self.font_size)
        # 调用 TextBox 类的 handle_resize 方法
        if hasattr(self, 'game') and hasattr(self.game, 'text_box'):
            self.game.text_box.handle_resize(event)

    def execute_option(self, option):
        """执行主菜单选项"""
        if option == "退出游戏":
            self.running = False
            pygame.quit()
            sys.exit()
        elif option == "击键特征可视化":
            # 进入击键特征可视化界面
            visualization = KeystrokeVisualization(self.screen)
            visualization.run()
        elif option == "开始游戏":
            self.current_menu = "sub"

    def execute_sub_option(self, option):
        if option == "新用户":
            self.input_name_active = True
            self.name_error_message = ""
        elif option == "已有用户":
            self.start_game("已有用户", username=None)

    def start_game(self, option, username=None):
        self.should_start_game = True
        self.start_option = option
        self.username = username if option == "新用户" else None
        self.is_existing_user = (option == "已有用户")
        
    def run(self):
        """运行菜单主循环并返回用户选择"""
        while self.running:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    return None
                self.handle_event(event)
            
            self.draw()
            pygame.display.flip()
            
            # 当用户做出选择时返回结果
            if hasattr(self, 'should_start_game'):
                # 返回深拷贝的元组，避免任何引用残留
                result = (
                    str(self.username) if hasattr(self, 'username') else None,
                    bool(self.is_existing_user)
                )
                self.force_cleanup()
                return result
        
        return None  # 用户退出游戏

    def force_cleanup(self):
        """强制清理所有菜单状态"""
        attrs_to_remove = ['username', 'is_existing_user', 'should_start_game']
        for attr in attrs_to_remove:
            if hasattr(self, attr):
                delattr(self, attr)